/*
 * Copyright (C) 2012 mAPPn.Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.mol.market.ui;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.app.LocalActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TabHost;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabHost.TabSpec;
import android.widget.TextView;
import android.widget.ViewAnimator;

import com.mol.market.Constants;
import com.mol.market.R;
import com.mol.market.common.network.ApiAsyncTask;
import com.mol.market.common.network.MarketAPI;
import com.mol.market.common.util.ThemeManager;
import com.mol.market.common.util.TopBar;
import com.mol.market.common.util.Utils;
import com.mol.market.common.vo.TagsInfo;
import com.mol.market.common.widget.AppListAdapter;
import com.mol.market.common.widget.BaseActivity;
import com.mol.market.common.widget.CategoryTagView;
import com.mol.market.common.widget.CategoryTagView.TagViewListener;
import com.mol.market.common.widget.GridViewNoScroll;
import com.mol.market.common.widget.LoadingDrawable;
import com.mol.market.common.widget.NavigationTitle;

/**
 * 分类列表,使用GridView布局。
 * @author Chaos	
 * @since 0.9.6
 * @date 2012-10-15
 */
public class CategoryGridActivity extends BaseActivity implements OnItemClickListener,
        OnClickListener, ApiAsyncTask.ApiRequestListener,TagViewListener {

    // Tag中"更多标签的ID"
    private static final String ID_GETMORE = "get-more";
    // 动画时间
    private static final long ANIMATION_DURATION = 450;
    // 最多显示标签的数量
    private static final int MAX_SHOW_TAGS = 7;
    // 界面动画
    private ViewAnimator mViewAnimator;
    // 当前界面深度
    private Hierarchy mCurrentHierarchy = Hierarchy.CATEGORY;
    // Tab id
    private static final String TAB_POP = "pop";
    private static final String TAB_NEW = "new";
    private TabHost mTabHost;
    private ViewGroup mAncestor = null;
    // 顶部阴影
    private ImageView mShadow;
    private LayoutInflater mInflater;
    // 数据的状态
    private DataState mTopDataState = DataState.WAITING;
    private DataState mBottomDataState = DataState.WAITING;
    private ArrayList<HashMap<String, Object>> mTopData;
    private ArrayList<HashMap<String, Object>> mBottomData;
    
    // 检查用户是否更换主题
    private BroadcastReceiver mThemeReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            TopBar.initSkin(mSession, CategoryGridActivity.this);
            initSkin();
        }
    };

    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_category_grid_layout);
        
        mInflater = LayoutInflater.from(getApplicationContext());

        IntentFilter themeFilter = new IntentFilter(Constants.BROADCAST_CHANGE_THEME);
        registerReceiver(mThemeReceiver, themeFilter);
        
        // 获取屏幕宽度
        initAnimation(getWindowManager().getDefaultDisplay().getWidth());
        initTopBar();
        initView(getWindowManager().getDefaultDisplay().getHeight());

        //TODO 请求标签列表
//        MarketAPI.getCategoryTags(getApplicationContext(), this);
        //请求分类信息
        MarketAPI.getAllCategory(getApplicationContext(), this);
    }

    @Override
    protected void onResume() {
        super.onResume();
//        TCAgent.onResume(getParent());
    }

    @Override
    protected void onPause() {
        super.onPause();
//        TCAgent.onPause(getParent());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mThemeReceiver);
    }

    private void initView(int height) {
        // find the ancestor.
        mAncestor = (ViewGroup) findViewById(R.id.ll_gridviewGroup);
        // find the animator.
        mViewAnimator = (ViewAnimator) this.findViewById(R.id.va_hirachy);
        // first into the CategoryActivity, should be show loading view.
        setLoadingState(State.WAITING);
    }
    
    /**
     * 初始化Topbar
     */
    private void initTopBar() {
        TopBar.createTopBar(mSession, this, 
                new View[] { 
                    findViewById(R.id.top_bar_title),
                    findViewById(R.id.top_bar_search) }, 
                new int[] { 
                    View.VISIBLE, 
                    View.VISIBLE },
                getString(R.string.sort_top_title));
    }

    /*
     * 初始化数据Adapter
     */
    private ListAdapter initAdapter(ArrayList<HashMap<String, Object>> data) {
        AppListAdapter adapter = new AppListAdapter(getApplicationContext(), 
                data,
                R.layout.activity_category_grid_list_item,
                new String[] {
                        Constants.KEY_CATEGORY_ICON_URL, 
                        Constants.KEY_CATEGORY_NAME,
                        }, 
                new int[] {
                        R.id.iv_icon, 
                        R.id.tv_category_name,
                        }
        );
        adapter.setActivity(getParent());
        return adapter;
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        if (mViewAnimator.getInAnimation() != null && !mViewAnimator.getInAnimation().hasEnded()) {
            // animation is not end yet
            return;
        }

        Object metadata = parent.getAdapter().getItem(position);
        if (metadata == null || !(metadata instanceof HashMap)) {
            Utils.W("metadata error , metadata == null or not instanceof HashMap");
            return;
        }
        
        if(mCurrentHierarchy == Hierarchy.PRODUCT_LIST){
            //fix bug：避免连续点击，重复响应事件。
            return ;
        }
        
        mCurrentHierarchy = Hierarchy.PRODUCT_LIST;

        mViewAnimator.setOutAnimation(sLeftOutAnimation);
        mViewAnimator.setInAnimation(sRighttInAnimation);

        @SuppressWarnings("unchecked")
        HashMap<String, Object> item = (HashMap<String, Object>) metadata;
        updateNavigationTitle((String) item.get(Constants.KEY_CATEGORY_NAME), true);

        String categoryId = (String) item.get(Constants.KEY_CATEGORY_ID);
        initAppListView(categoryId);

        
        mViewAnimator.showNext();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.no_data:
            if (mCurrentHierarchy == Hierarchy.CATEGORY) {
                setLoadingState(State.WAITING);
                MarketAPI.getAllCategory(getApplicationContext(), this);
            }
            break;
        case R.id.rl_category_tags:
            Utils.trackEvent(this, Constants.TAG,
                Constants.CLICK_CATEGORY_TAG);
            Utils.jumpToPage(this, CategoryTagsActivity.class, false);
            break;
        default:
            break;
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onSuccess(int method, Object obj) {

        if (obj == null) {
            return;
        }

        if (method == MarketAPI.ACTION_GET_ALL_CATEGORY) {
            mBottomData = (ArrayList<HashMap<String, Object>>) obj;
            mBottomDataState = DataState.SUCCESS;

        } else if (method == MarketAPI.ACTION_GET_CATEGORY_TAGS) {
            mTopData = (ArrayList<HashMap<String, Object>>) obj;
            mTopDataState = DataState.SUCCESS;
        }

        if (mBottomDataState == DataState.SUCCESS && mTopDataState == DataState.SUCCESS) {
            setLoadingState(State.HIDING);
            showIndicator(mTopData);
            update(mAncestor, mBottomData);

            mTopDataState = DataState.WAITING;
            mBottomDataState = DataState.WAITING;
        }
    }
    
    private void showIndicator(ArrayList<HashMap<String, Object>> result) {
        addSeparator(getString(R.string.label), mAncestor);
        addTagView(this, mAncestor, getDataFromResult(result));
    }

    /**
     * update the ancestor
     */
    @SuppressWarnings("unchecked")
    private void update(final ViewGroup ancestor, ArrayList<HashMap<String, Object>> data) {
        /*
         * step.1:服务器传回的数据包含了二级分类信息，0.9.6要求取消二级分类信息，
         *        所以我们要对信息进行判断，如果包含分类信息，则将分类信息展示到
         *        一个新的GridView上，并在其之上添加一个Separator. 
         * step.2:如果进行了step.1，则需要在data中去除信息，避免重复显示。
         * 
         * notice:data将被缓存，使用的依然是data的引用，所以不可以直接修改data，
         *        否则将会对 Adapter产生影响。
         */

        //copying data is for reuse, and shallow copy is enough
        ArrayList<HashMap<String, Object>> garbage = (ArrayList<HashMap<String, Object>>) data.clone();
        if (garbage.size() == 0) {
            //The server returned empty data
            this.onError(MarketAPI.ACTION_GET_ALL_CATEGORY, 0);
            return ;
        }
        
        //将电子书置于最后的位置，这里将电子书相关信息保存下来
        String eBook = "电子书";
        ArrayList<HashMap<String, Object>> eBookData = null;

        //handle data
        for (HashMap<String, Object> item : data) {
            Object subData = item.get(Constants.KEY_SUB_CATEGORY);
            if (subData != null) {
                // 含有二级分类
                String subCategoryName = (String) item.get(Constants.KEY_CATEGORY_NAME);
                if(eBook.equals(subCategoryName)){
                    //如果是电子书 ，保存起来
                    eBookData = (ArrayList<HashMap<String, Object>>) subData;
                    garbage.remove(item);
                    continue ;
                }
                addSeparator(subCategoryName, ancestor);
                addGridView((ArrayList<HashMap<String, Object>>) subData, ancestor);
                garbage.remove(item);
            }
        }

        //using "garbage" init
        addSeparator(getString(R.string.rank_tab_app), ancestor);
        addGridView(garbage, ancestor);
        
        //如果电子书存在，添加电子书.
        if(eBookData != null){
            addSeparator(eBook, ancestor);
            addGridView(eBookData, ancestor);
        }
    }

    public void onError(int method, int statusCode) {
        
        if (method == MarketAPI.ACTION_GET_ALL_CATEGORY) {
            mBottomDataState = DataState.ERROR;

        } else if (method == MarketAPI.ACTION_GET_CATEGORY_TAGS) {
            mTopDataState = DataState.ERROR;
        }

        if (mBottomDataState == DataState.ERROR || mTopDataState == DataState.ERROR) {
            setLoadingState(State.NODATA);
        }
    }

    @SuppressWarnings("deprecation")
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (KeyEvent.KEYCODE_BACK == keyCode 
                && mCurrentHierarchy != Hierarchy.CATEGORY) {
            
            if (mViewAnimator.getInAnimation() != null 
                    && !mViewAnimator.getInAnimation().hasEnded()) {
                // animation is not end yet
                return true;
            }
            
            mViewAnimator.setOutAnimation(sRightOutAnimation);
            mViewAnimator.setInAnimation(sLeftInAnimation);
            //pop title
            updateNavigationTitle(null, false);
            //add shadow
            if (mTabHost != null) {
                mShadow.setVisibility(View.VISIBLE);
                LocalActivityManager lam = getLocalActivityManager();
                lam.removeAllActivities();
            }
            //remove current view
            View curView = mViewAnimator.getCurrentView();
            mViewAnimator.showPrevious();
            mViewAnimator.removeView(curView);
            
            mCurrentHierarchy = Hierarchy.CATEGORY;
            
            //让ScrollView的滚动条回归到初始状态
            restoreScrollIfNeed(mViewAnimator.getCurrentView());
            return true;
        }
        return getParent().onKeyDown(keyCode, event);
    }
    
    /**
     * @param view
     * @return if success return true.
     */
    private boolean restoreScrollIfNeed(View view){
        if(isScrollView(view)){
            restoreScroll((ScrollView)view, view.getScrollX(), view.getScrollY());
            return true;
        }
        return false;
    }
    /**
     * 因为ScrollView嵌套自带滚动条的View会导致回到这个页面时，
     * 滚动条会有一定的偏移。这个方法可以让ScrollView的滚动条回到特定位置。
     * @param scrollView
     */
    private void restoreScroll(ScrollView scrollView,int x,int y){
        scrollView.smoothScrollTo(x, y);
    }
    
    private boolean isScrollView(View view){
        return view != null && view instanceof ScrollView;
    }

    /*
     * 更新导航栏标题
     */
    private void updateNavigationTitle(String title, boolean isPush) {
        NavigationTitle titleView = (NavigationTitle) findViewById(R.id.top_bar_title);
        if (isPush) {
            titleView.pushTitle(title);
        } else {
            titleView.popTitle();
        }
    }

    /* 分级列表动画 */
    private static TranslateAnimation sLeftOutAnimation;
    private static TranslateAnimation sLeftInAnimation;
    private static TranslateAnimation sRightOutAnimation;
    private static TranslateAnimation sRighttInAnimation;

    /*
     * 初始化分级列表移动动画
     */
    private void initAnimation(int width) {
        sLeftOutAnimation = new TranslateAnimation(0, -width, 0, 0);
        sRighttInAnimation = new TranslateAnimation(width, 0, 0, 0);
        sLeftInAnimation = new TranslateAnimation(-width, 0, 0, 0);
        sRightOutAnimation = new TranslateAnimation(0, width, 0, 0);
        sLeftOutAnimation.setDuration(ANIMATION_DURATION);
        sRighttInAnimation.setDuration(ANIMATION_DURATION);
        sLeftInAnimation.setDuration(ANIMATION_DURATION);
        sRightOutAnimation.setDuration(ANIMATION_DURATION);
    }

    private void initSkin() {
        if (mCurrentHierarchy == Hierarchy.PRODUCT_LIST) {
            View tabBg = findViewById(R.id.tab_frame_layout);
            tabBg.setBackgroundResource(ThemeManager.getResource(mSession, ThemeManager.KEY_TAB_BG));
            for (int i = 0; i < 2; i++) {
                TextView v = (TextView) mTabHost.getTabWidget().getChildTabViewAt(i);

                if (i == 0) {
                    Utils.createTabView(getApplicationContext(), mSession,
                            getString(R.string.sort_tab_pop), -1, v);
                } else if (i == 1) {
                    Utils.createTabView(getApplicationContext(), mSession,
                            getString(R.string.sort_tab_new), 1, v);
                }
            }
        }
    }

    /**
     * 初始化应用列表（包含最热[装机量]和最新列表[上升最快]）
     * FIXME 两个TabHost中间有一根线
     */
    @SuppressWarnings("deprecation")
    private void initAppListView(String categoryId) {

        mShadow = (ImageView) findViewById(R.id.shadow);
        mShadow.setVisibility(View.GONE);

        mInflater.inflate(R.layout.common_tab_host, mViewAnimator);
        mTabHost = (TabHost) findViewById(android.R.id.tabhost);
        mTabHost.setup(getLocalActivityManager());
        mTabHost.getTabWidget().setPadding(mSession.mTabMargin72, 0, mSession.mTabMargin72, 0);
        FrameLayout fl = (FrameLayout) mTabHost.findViewById(R.id.tab_frame_layout);
        fl.setBackgroundResource(ThemeManager.getResource(mSession, ThemeManager.KEY_TAB_BG));
        Intent popIntent = new Intent(getApplicationContext(), ProductListActivity.class);
        popIntent.putExtra(Constants.EXTRA_SORT_TYPE, Constants.ORDER_TYPE_INSTALLED_NUM);
        popIntent.putExtra(Constants.EXTRA_CATEGORY_ID, categoryId);
        TabSpec tab1 = mTabHost
                .newTabSpec(TAB_POP)
                .setIndicator(
                        Utils.createTabView(getApplicationContext(), mSession,
                                getString(R.string.sort_tab_pop), -1, null)).setContent(popIntent);
        mTabHost.addTab(tab1);

        Intent newIntent = new Intent(getApplicationContext(), ProductListActivity.class);
        newIntent.putExtra(Constants.EXTRA_SORT_TYPE, Constants.ORDER_TYPE_TIME);
        newIntent.putExtra(Constants.EXTRA_CATEGORY_ID, categoryId);
        TabSpec tab2 = mTabHost
                .newTabSpec(TAB_NEW)
                .setIndicator(
                        Utils.createTabView(getApplicationContext(), mSession,
                                getString(R.string.rank_tab_fast), 1, null)).setContent(newIntent);
        mTabHost.addTab(tab2);
        
        mTabHost.setOnTabChangedListener(new OnTabChangeListener() {

            @Override
            public void onTabChanged(String tabId) {
                if (TAB_NEW.equals(tabId)) {
                    Utils.trackEvent(getApplicationContext(), Constants.GROUP_3,
                            Constants.CLICK_SUB_CATEGORY_NEW_TAB);
                }
            }
        });
    }
    
    /**
     * create a TagView and add it to ancestor
     * @param ancestor
     */
    private void addTagView(Context context, ViewGroup ancestor, List<TagsInfo> list){
        CategoryTagView tagView = new CategoryTagView(context);
        tagView.setTags(list);
        tagView.setTagsViewOnClickListener(this);
        
        ancestor.addView(tagView);
    }
    
    /**
     * <p>从结果中取得指定规则的数据。</p>
     * 规则：取返回数据的第一条，且数量小于{@link #MAX_SHOW_TAGS}。
     * @param result
     * @return
     */
    @SuppressWarnings({"unchecked" })
    private List<TagsInfo> getDataFromResult(ArrayList<HashMap<String, Object>> result) {

        if (result.size() == 0) {
            return null;
        }

        Object illusion = result.get(0).get(Constants.KEY_TAGS);
        List<TagsInfo> resultList = null;

        if (illusion != null && illusion instanceof List) {

            resultList = new ArrayList<TagsInfo>();

            List<TagsInfo> tagsList = (List<TagsInfo>) illusion;
            if (tagsList.size() > MAX_SHOW_TAGS) {
                // 超过了指定数量，截取之前的信息
                resultList.addAll(tagsList.subList(0, MAX_SHOW_TAGS));
            } else {
                // 没超过指定数量，直接返回。
                resultList.addAll(tagsList);
            }
            addMore(resultList);
        }

        return resultList;
    }
    
    /**
     * 增加“查看更多"
     */
    private void addMore(List<TagsInfo> list) {
        list.add(new TagsInfo().setTagId(ID_GETMORE).setTagName(getString(R.string.getmore)));
    }

    /**
     * create a GridView and add it to ancestor
     * 
     * @param dataSoucre
     * @param ancestor
     */
    private void addGridView(ArrayList<HashMap<String, Object>> dataSoucre, ViewGroup ancestor) {
        // inflater the GridView
        GridViewNoScroll gridview = (GridViewNoScroll) mInflater.inflate(
                R.layout.item_gridview_no_scroll, null);
        gridview.setOnItemClickListener(this);
        // bind adapter
        gridview.setAdapter(initAdapter(dataSoucre));
        // add GridView to the ancestor
        ancestor.addView(gridview);
    }

    /**
     * create a Separator and add it to ancestor
     * 
     * @param title
     * @param ancestor
     */
    private void addSeparator(String title, ViewGroup ancestor) {
        // inflater the GridView
        View separator = mInflater.inflate(R.layout.activity_install_nessary_list_separator, null);
        TextView textView = (TextView) separator.findViewById(R.id.tv_name);
        textView.setText(title);
        // add Separator to the ancestor
        ancestor.addView(separator);
    }
    
    /**
     * 界面的层级关系
     * @author Chaos	
     *
     */
    enum Hierarchy{
        //当前分类，一级界面
        CATEGORY,
        //产品列表，二级界面
        PRODUCT_LIST;
    }

    /**
     * 数据的状态
     * @author Chaos	
     *
     */
    enum DataState{
       //数据请求--等待响应
        WAITING,
       //数据返回--成功
        SUCCESS,
       //数据返回--失败
        ERROR
    }
    
    /**
     * loading state
     * @author Chaos	
     *
     */
    enum State{
        //隐藏Loading
        HIDING,
        //等待
        WAITING,
        //无数据
        NODATA
    }
    
    private FrameLayout mLoading  = null;
    private ProgressBar mProgress = null;
    private TextView mNoData      = null;
    
    /**
     * 设置等待框的状态
     * @param state
     */
    private void setLoadingState(State state){
        // init loading
        if (mLoading == null || mProgress == null || mNoData == null) {
            mLoading = (FrameLayout) findViewById(R.id.loading);
            mProgress = (ProgressBar) mLoading.findViewById(R.id.progressbar);
            mProgress.setIndeterminateDrawable(new LoadingDrawable(getApplicationContext()));
            mNoData = (TextView) mLoading.findViewById(R.id.no_data);
            mNoData.setOnClickListener(this);
        }

        switch (state) {
        case HIDING:
            mLoading.setVisibility(View.GONE);
            mNoData.setVisibility(View.GONE);
            mProgress.setVisibility(View.GONE);
            break;
        case NODATA:
            mLoading.setVisibility(View.VISIBLE);
            mNoData.setVisibility(View.VISIBLE);
            mProgress.setVisibility(View.GONE);
            break;
        case WAITING:
            mLoading.setVisibility(View.VISIBLE);
            mNoData.setVisibility(View.GONE);
            mProgress.setVisibility(View.VISIBLE);
            break;
        }
    }

    @Override
    public void onTagsViewClick(View v, TagsInfo tag) {
        if(tag == null){
            return ;
        }
        
        if(ID_GETMORE.equals(tag.getTagId())){
            Utils.trackEvent(this, Constants.TAG,
                    Constants.CLICK_CATEGORY_TAG);
            Utils.jumpToPage(this, 
                    CategoryTagsActivity.class, 
                    false);
        }else{
            Utils.trackEvent(this, Constants.TAG,
                    String.format(Constants.CLICK_TAG, tag.getTagName()));
            Utils.jumpToPage(this, TagsListActivity.class, false, 
                    new String[] {
                        TagsListActivity.TAGS_ID, 
                        TagsListActivity.TAGS_NAME }, 
                    new Serializable[] {
                        tag.getTagId(), 
                        tag.getTagName() }
            );
        }
    }
}
